/* Example for analogContinuousRead
 *  It measures continuously the voltage on pin A9,
 *  Write v and press enter on the serial console to get the value
 *  Write c and press enter on the serial console to check that the conversion
 * is taking place, Write t to check if the voltage agrees with the comparison
 * in the setup() Write s to stop the conversion, you can restart it writing r.
 */

#include <ADC.h>
#include <ADC_util.h>

const int readPin = A9;  // ADC0
const int readPin2 = A3; // ADC1
const int readPin3 = A2; // ADC0 or ADC1

ADC *adc = new ADC(); // adc object

void setup() {

  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(readPin, INPUT_DISABLE);
  pinMode(readPin2, INPUT_DISABLE);
  pinMode(readPin3, INPUT_DISABLE);

  pinMode(A10, INPUT_DISABLE); // Diff Channel 0 Positive
  pinMode(A11, INPUT_DISABLE); // Diff Channel 0 Negative

#ifdef ADC_DUAL_ADCS
  pinMode(A12, INPUT_DISABLE); // Diff Channel 3 Positive
  pinMode(A13, INPUT_DISABLE); // Diff Channel 3 Negative
#endif

  Serial.begin(9600);

  ///// ADC0 ////
  // reference can be ADC_REFERENCE::REF_3V3, ADC_REFERENCE::REF_1V2 (not for
  // Teensy LC) or ADC_REFERENCE::REF_EXT.
  // adc->adc0->setReference(ADC_REFERENCE::REF_1V2); // change all 3.3 to 1.2
  // if you change the reference to 1V2

  adc->adc0->setAveraging(16);  // set number of averages
  adc->adc0->setResolution(16); // set bits of resolution

  // it can be any of the ADC_CONVERSION_SPEED enum: VERY_LOW_SPEED, LOW_SPEED,
  // MED_SPEED, HIGH_SPEED_16BITS, HIGH_SPEED or VERY_HIGH_SPEED see the
  // documentation for more information additionally the conversion speed can
  // also be ADACK_2_4, ADACK_4_0, ADACK_5_2 and ADACK_6_2, where the numbers
  // are the frequency of the ADC clock in MHz and are independent on the bus
  // speed.
  adc->adc0->setConversionSpeed(
      ADC_CONVERSION_SPEED::VERY_LOW_SPEED); // change the conversion speed
  // it can be any of the ADC_MED_SPEED enum: VERY_LOW_SPEED, LOW_SPEED,
  // MED_SPEED, HIGH_SPEED or VERY_HIGH_SPEED
  adc->adc0->setSamplingSpeed(
      ADC_SAMPLING_SPEED::MED_SPEED); // change the sampling speed

  // always call the compare functions after changing the resolution!
  // adc->adc0->enableCompare(1.0/3.3*adc->getMaxValue(), 0); // measurement
  // will be ready if value < 1.0V
  // adc->adc0->enableCompareRange(1.0*adc->adc0->getMaxValue()/3.3, 2.0*adc->adc0->getMaxValue()/3.3,
  // 0, 1); // ready if value lies out of [1.0,2.0] V

  // If you enable interrupts, notice that the isr will read the result, so that
  // isComplete() will return false (most of the time)
  adc->adc0->enableInterrupts(adc0_isr);

  adc->adc0->startContinuous(readPin);
// adc->startContinuousDifferential(A10, A11, ADC_0);

////// ADC1 /////
#ifdef ADC_DUAL_ADCS
  adc->adc1->setAveraging(16);  // set number of averages
  adc->adc1->setResolution(16); // set bits of resolution
  adc->adc1->setConversionSpeed(
      ADC_CONVERSION_SPEED::MED_SPEED); // change the conversion speed
  adc->adc1->setSamplingSpeed(
      ADC_SAMPLING_SPEED::MED_SPEED); // change the sampling speed

  // adc->adc0->setReference(ADC_REFERENCE::REF_1V2);

  // always call the compare functions after changing the resolution!
  // adc->adc0->enableCompare(1.0/3.3*adc->adc0->getMaxValue(), 0); //
  // measurement will be ready if value < 1.0V
  // adc->adc0->enableCompareRange(1.0*adc->adc0->getMaxValue()/3.3, 2.0*adc->adc0->getMaxValue()/3.3,
  // 0, 1); // ready if value lies out of [1.0,2.0] V

  // If you enable interrupts, note that the isr will read the result, so that
  // isComplete() will return false (most of the time)
  // adc->adc1->enableInterrupts(adc1_isr);

  adc->adc1->startContinuous(readPin2);
  // adc->adc1->startContinuousDifferential(A12, A13);

#endif

  delay(500);
}

int value = 0;
int value2 = 0;
char c = 0;

void loop() {

  if (Serial.available()) {
    c = Serial.read();
    if (c == 'c') { // conversion active?
      Serial.print("Converting? ADC0: ");
      Serial.println(adc->adc0->isConverting());
#ifdef ADC_DUAL_ADCS
      Serial.print("Converting? ADC1: ");
      Serial.println(adc->adc1->isConverting());
#endif
    } else if (c == 's') { // stop conversion
      adc->adc0->stopContinuous();
      Serial.println("Stopped");
    } else if (c == 't') { // conversion successful?
      Serial.print("Conversion successful? ADC0: ");
      Serial.println(adc->adc0->isComplete());
#ifdef ADC_DUAL_ADCS
      Serial.print("Conversion successful? ADC1: ");
      Serial.println(adc->adc1->isComplete());
#endif
    } else if (c == 'r') { // restart conversion
      Serial.println("Restarting conversions ");
      adc->adc0->startContinuous(readPin);
      // adc->startContinuousDifferential(A10, A11, ADC_0);
    } else if (c == 'v') { // value
      Serial.print("Value ADC0: ");
      value = (uint16_t)adc->adc0
                  ->analogReadContinuous(); // the unsigned is necessary for 16
                                            // bits, otherwise values larger
                                            // than 3.3/2 V are negative!
      Serial.println(value * 3.3 / adc->adc0->getMaxValue(), DEC);
#ifdef ADC_DUAL_ADCS
      Serial.print("Value ADC1: ");
      value2 = (uint16_t)adc->adc1
                   ->analogReadContinuous(); // the unsigned is necessary for 16
                                             // bits, otherwise values larger
                                             // than 3.3/2 V are negative!
      Serial.println(value2 * 3.3 / adc->adc1->getMaxValue(), DEC);
#endif
    } else if (c == 'n') { // new single conversion on readPin3
      // this shows how even when both ADCs are busy with continuous
      // measurements you can still call analogRead, it will pause the
      // conversion, get the value and resume the continuous conversion
      // automatically.
      Serial.print("Single read on readPin3: ");
      Serial.println(adc->adc0->analogRead(readPin3) * 3.3 /
                         adc->adc0->getMaxValue(),
                     DEC);
    }
  }

  // Print errors, if any.
  if (adc->adc0->fail_flag != ADC_ERROR::CLEAR) {
    Serial.print("ADC0: ");
    Serial.println(getStringADCError(adc->adc0->fail_flag));
  }
#ifdef ADC_DUAL_ADCS
  if (adc->adc1->fail_flag != ADC_ERROR::CLEAR) {
    Serial.print("ADC1: ");
    Serial.println(getStringADCError(adc->adc1->fail_flag));
  }
#endif

  // digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));

  delay(100);
}

void adc0_isr(void) {
  adc->adc0->analogReadContinuous();
  digitalWriteFast(LED_BUILTIN,
                   !digitalReadFast(LED_BUILTIN)); // Toggle the led
}
#ifdef ADC_DUAL_ADCS
void adc1_isr(void) {
  adc->adc1->analogReadContinuous();
  digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
}
#endif
